package org.alesv.common.webapp.controller;

import java.io.IOException;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.context.MessageSource;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.multipart.support.ByteArrayMultipartFileEditor;

/**
 * Controlador por defecto.
 * 
 */
public abstract class BaseController {

	/** logger por defecto. */
	private static final Logger log = LoggerFactory
			.getLogger(BaseController.class);

	/**
	 * Cadena forward.
	 */
	public static final String FORWARD = "forward:";
	/**
	 * Cadena redirect.
	 */
	public static final String REDIRECT = "redirect:";

	/**
	 * Vista de retorno.
	 */
	private String exitView;

	/**
	 * Inyección del fichero de mensajes i18n.
	 */
	@Autowired(required = true)
	@Qualifier("messageSource")
	private MessageSource messageSource;

	/* ****************
	 * * i18n METHODS * ****************
	 */

	/** Methods for handling i18n messages. **/
	protected final String getMessage(String messageKey) {
		return getMessage(messageKey, Locale.getDefault());
	}

	/** Methods for handling i18n messages. **/
	protected final String getMessage(String messageKey, Locale locale) {
		return messageSource.getMessage(messageKey, null, locale);
	}

	/** Methods for handling i18n messages. **/
	protected final String getMessage(String messageKey, String argument,
			Locale locale) {
		return this.getMessage(messageKey, new Object[] { argument }, locale);
	}

	/** Methods for handling i18n messages. **/
	protected final String getMessage(String messageKey, Object[] arguments,
			Locale locale) {
		return messageSource.getMessage(messageKey, arguments, locale);
	}

	/** Methods for handling i18n messages. **/
	@SuppressWarnings("unchecked")
	private final ArrayList<String> getMessages(HttpServletRequest request) {
		Object object = request.getSession().getAttribute("messages");

		if (object == null) {
			return new ArrayList<String>();
		}

		return (ArrayList<String>) object;
	}

	/** Methods for handling i18n messages. **/
	private final void setMessages(HttpServletRequest request,
			List<String> messages) {
		if (messages != null) {
			request.getSession().setAttribute("messages", messages);
		}
	}

	/** Methods for handling i18n messages. **/
	protected final void clearMessages(HttpServletRequest request) {
		List<String> messages = getMessages(request);

		messages.clear();

		setMessages(request, messages);
	}

	/** Methods for handling i18n messages. **/
	protected final void saveMessage(HttpServletRequest request, String message) {
		List<String> messages = getMessages(request);

		messages.add(message);

		setMessages(request, messages);
	}

	/** Methods for handling i18n messages. **/
	protected final void saveMessageKey(HttpServletRequest request,
			String messageKey) {
		saveMessage(request, getMessage(messageKey, request.getLocale()));
	}

	/** Methods for handling i18n messages. **/
	protected final void saveMessageKey(HttpServletRequest request,
			String messageKey, String argument) {
		saveMessage(request,
				getMessage(messageKey, argument, request.getLocale()));
	}

	/** Methods for handling i18n messages. **/
	protected final void saveMessageKey(HttpServletRequest request,
			String messageKey, Object[] arguments) {
		saveMessage(request,
				getMessage(messageKey, arguments, request.getLocale()));
	}

	/**************************
	 ** Data Handling Methods **
	 **************************/

	/** Method for clearing session. **/
	protected final void clearSession(SessionStatus status) {
		status.setComplete();
	}

	/** Method for data binding. **/
	@InitBinder
	public final void initBinder(Locale locale, WebDataBinder binder) {
		NumberFormat nf = NumberFormat.getNumberInstance();
		binder.registerCustomEditor(Integer.class, null,
				new CustomNumberEditor(Integer.class, nf, true));
		binder.registerCustomEditor(Long.class, null, new CustomNumberEditor(
				Long.class, nf, true));
		binder.registerCustomEditor(byte[].class,
				new ByteArrayMultipartFileEditor());

		SimpleDateFormat dateFormat = new SimpleDateFormat(getMessage(
				"date.format", locale));
		dateFormat.setLenient(false);
		binder.registerCustomEditor(Date.class, null, new CustomDateEditor(
				dateFormat, true));
	}

	/* **********************
	 * * NAVIGATION METHODS * **********************
	 */

	/**
	 * Obtiene la vista de salida.
	 */
	protected final String getExitView() {
		return exitView;
	}

	/**
	 * Establece la vista de salida del controlador.
	 * 
	 * @param exitView
	 *            nombre de la vista
	 */
	protected final void setExitView(String exitView) {
		this.exitView = exitView;
	}

	/**
	 * Orden de salir de un controlador.
	 * 
	 * @param status
	 *            estado de la sesión.
	 * @return la página a la que se redirige.
	 */
	protected final String exit(SessionStatus status) {
		clearSession(status);

		return new StringBuilder(REDIRECT).append(exitView).toString();
	}

	/**
	 * @param forwardView
	 * @return
	 */
	protected final String forward(String forwardView) {
		return new StringBuilder(FORWARD).append(forwardView).toString();
	}

	/**
	 * @param redirectView
	 * @return
	 */
	protected final String redirect(String redirectView) {
		return new StringBuilder(REDIRECT).append(redirectView).toString();
	}

	/** Method for redirecting pages. **/
	protected final void redirect(HttpServletResponse response,
			String redirectView) {
		try {
			response.sendRedirect(redirectView);
		} catch (IOException ex) {
			log.error(ex.getMessage());
		}
	}

	/** Method for redirecting pages. **/
	protected final int filterPage(Integer page) {
		page = (page != null) ? page.intValue() : 1;
		return (page > 0) ? page : 1;
	}

	/***********************
	 ** VALIDATION METHODS **
	 ***********************/

	/** Method for validating an object using a validator. **/
	protected final void validate(Validator validator, Object object,
			BindingResult result) {
		if (validator != null) {
			validator.validate(object, result);
		}
	}

	/** Method for validating an object using a group of validators. **/
	protected final void validate(Validator[] validators, Object object,
			BindingResult result) {
		if (validators != null) {
			for (Validator validator : validators) {
				validator.validate(object, result);
			}
		}
	}
}
